
#ifndef __MUSICENGINE_H__
#define __MUSICENGINE_H__

#include "NetworkEngine/NetworkMusicFile.h"
#include "NetworkEngine/NetworkLyricFile.h"

namespace SPlayer
{
    namespace Network
    { }
    namespace Music
    {
        using namespace Network;
        ref class MusicEventDispatcher
        {
        public:
            System::Action<System::String ^/*filepath*/> ^onPlayed;
            System::Action ^onStoped;
            System::Action ^onPaused;
            System::Action ^onContinued;
            System::Action ^onFinished;
        };

        ref class MusicEngine : public IrrKlang::ISoundStopEventReceiver
        {
        private:
            MusicEngine();
        public:
            static bool init();

            // methods:
        public:
            void stop();
            bool pause();
            bool continuePlay();
            bool playLocalFile(System::String ^filename);
            bool playNetworkFile(System::String ^networkFileName);
            bool playCachedFile(System::String ^networkFileName);

            bool preparePlayNetworkFile(System::String ^networkFileName);
            void onNetworkFilePrepared();
            // music properties:
        public:
            property bool hasMusic { bool get(); }
            /*! @brief playing music's length, in milliseconds. */
            property unsigned length { unsigned get(); }
            property unsigned playOffset { unsigned get(); void set(unsigned offset); }
            /*! @brief volume between 0(mute) and 1(full volumn). */
            property float volume{ float get(); void set(float volume); }

            // variables:
        public:
            MusicEventDispatcher ^eventDispatcher = gcnew MusicEventDispatcher;

            // static properties:
        public:
            static MusicEngine ^musicEngine = nullptr;

            // action functions:
        public:
            virtual void onSoundAutoStopped(IrrKlang::ISound^ sound, IrrKlang::StopEventCause reason, System::Object^ userData)
                = IrrKlang::ISoundStopEventReceiver::OnSoundStopped;

            // member variables for internal usage:
        private:
            bool isNetworkPlaying = false; // TODO : this is not good. Use a class to handle this
            Network::NetworkMusicFile ^networkMusicFile = nullptr;/* Network file to play*/
            Network::NetworkLyricFile ^networkLyricFile = nullptr;/* Network file to play*/

            IrrKlang::ISoundEngine ^_irrEngine = nullptr;
            System::Object ^_irrSoundMutex = gcnew System::Object;
            IrrKlang::ISound ^_irrSound = nullptr;
        };



        /* Lambda creator for C++/CLI */
        ref class NetworkFileReadableTracker
        {
        public:
            NetworkFileReadableTracker(NetworkMusicFile ^file) : networkFile(file)
            { }

            void traceReadable(int offset, int size, Action ^onReadable, int millsecondTimeout, Action ^onTimeout)
            {
                this->offset = offset;
                this->size = size;
                this->onReadable = onReadable;
                this->endtime = DateTime::Now.AddMilliseconds(millsecondTimeout);
                this->onTimeout = onTimeout;
                traceThread = gcnew Threading::Thread(
                    gcnew Threading::ThreadStart(this, &NetworkFileReadableTracker::thread_traceReadable));
                traceThread->Start();
            }
            void thread_traceReadable()
            {
                while (DateTime::Now < endtime)
                {
                    if (networkFile->isReadable(offset, size))
                    {
                        Common::Function::InvokeSync(onReadable);
                        return;
                    }
                    Threading::Thread::Sleep(1);
                }
                Common::Function::InvokeSync(onTimeout);
            }
        private:
            int offset;
            int size;
            DateTime endtime;
            Action ^onReadable;
            Action ^onTimeout;
        public:
            NetworkMusicFile ^networkFile;
            Threading::Thread ^ traceThread;
        };
    }
}
#endif // __MUSICENGINE_H__